package com.huiquan.vocab.service;

import com.huiquan.analysis.domain.User;
import com.huiquan.foundation.constant.BusinessContants;
import com.huiquan.framework.base.BaseService;
import com.huiquan.framework.base.ReturnCode;
import com.huiquan.framework.base.ReturnData;
import com.huiquan.framework.constant.BaseContants;
import com.huiquan.framework.dao.ActionRecordDao;
import com.huiquan.framework.domain.ActionRecord;
import com.huiquan.framework.utils.CollectionUtil;
import com.huiquan.framework.utils.GetListUtil;
import com.huiquan.framework.utils.RespHeaderUtil;
import com.huiquan.framework.utils.ReturnUtil;
import com.huiquan.homoionym.service.HomoionymSearchTermsService;
import com.huiquan.synonymy.dao.SynonymyDao;
import com.huiquan.synonymy.dao.SynonymyWordDao;
import com.huiquan.synonymy.domain.Synonymy;
import com.huiquan.synonymy.domain.SynonymyWord;
import com.huiquan.vocab.constant.VocabConstant;
import com.huiquan.vocab.dao.VocabElementChangeDao;
import com.huiquan.vocab.dao.VocabElementDao;
import com.huiquan.vocab.domain.*;
import com.huiquan.vocab.utils.VocabUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.*;
import java.util.regex.Pattern;


@Service
public class VocabElementService extends BaseService {

    @Autowired
    private VocabElementDao vocabElementDao;
    @Autowired
    private HomoionymSearchTermsService homoionymSearchTermsService;
    @Autowired
    private ActionRecordDao actionRecordDao;
    @Autowired
    private VocabElementWildcardService vocabElementWildcardService;
    @Autowired
    private SynonymyWordDao synonymyWordDao;
    @Autowired
    private SynonymyDao synonymyDao;

    public ModelAndView list(String startStr, String keyword, Integer flag, String propertyKey, String exactSearchFlag,
                             String replaceTypeKey, String countPerPageStr, Integer source) {
        LOGGER.info("List start!");
        boolean exactFlag = exactSearchFlag != null && exactSearchFlag.equals("1");

        // 将所有搜索条件集成到map中
        Map<String, Object> param = getSearchMap(keyword, exactFlag, replaceTypeKey, propertyKey, flag, source);

        // 根据条件获取数据总数
        int totalSize = vocabElementDao.retrieveSize(param);
        LOGGER.info("List totalSize=" + totalSize);

        // 获取分页相关信息
        Map<String, Integer> page = GetListUtil.getPagingParam(totalSize, startStr, countPerPageStr);

        int startIndex = page.get("startIndex");

        List<VocabElementDto> list = new ArrayList<>();
        if (startIndex < totalSize) {

            // 添加获取列表时需添加的参数
            setListParam(param, startIndex, page.get("countPerPage"), propertyKey, flag);

            list = getListByParam(param);

            LOGGER.info("Get list success!size = " + list.size());
        }

        Map<String, Object> map = new HashMap<>();
        map.putAll(page);
        map.put("list", list);

        if (!list.isEmpty()) {
            // 返回列表上多选框默认状态
            map.put("checked", getCheckedFlag(flag, propertyKey));
        }
        LOGGER.info("Get checked status success!");

        // 查询当前是否有未完成的小词
        ActionRecord ar = actionRecordDao.retrieveUncompletedByType(ActionRecord.TYPE_VOCAB_ELEMENT_SUBMIT);
        if (ar != null) {
            map.put("submitFlag", "1");
        }

        // 添加界面上的提示信息
        map.put("errorMsg", getErrorMsg(propertyKey));

        Map<String, String> showSearch = new LinkedHashMap<>();
        showSearch.put("keyword", "词语");
        map.put("showSearch", showSearch);
        map.put("propertyList", VocabConstant.elementProperty);
        map.put("propertyTempList", VocabConstant.elementPropertyTemp);
        LOGGER.info("List end!");

        return new ModelAndView("vocab/element_index", map);
    }

    private String getErrorMsg(String propertyKey) {

        String errorMsg = null;
        // 查询元素r同义词中是否有未校验词语，如果存在则提示
        List<String> wordList = vocabElementDao.retrieveSynonymUnchecked(propertyKey);
        if (wordList != null && !wordList.isEmpty()) {
            errorMsg = "元素r同义词中有未校验数据：";
            for (String word : wordList) {
                errorMsg += word + ",";
            }
        }

        return errorMsg;
    }

    private String getCheckedFlag(Integer flag, String propertyKey) {
        String checkFlag = null;
        if (flag == -1) {
            // 根据上一次的提交状态来展现本次的默认状态
            boolean checked = vocabElementDao.retrieveCheckedByLastCheck(propertyKey);
            if (checked) {
                checkFlag = "checked";
            }
        } else if (flag == 0) {
            checkFlag = "checked";
        }

        return checkFlag;
    }

    private List<VocabElementDto> getListByParam(Map<String, Object> param) {

        // 先获取核心内容
        List<VocabElementDto> list = vocabElementDao.retrieveMainList(param);

        // 获取所有的元素id
        String ids = "";
        for (VocabElementDto dto : list) {
            ids += dto.getId() + ",";
        }
        ids = ids.substring(0, ids.length() - 1);

        // 再获取附加属性
        List<Map<String, Object>> details = vocabElementDao.retrieveDetails(ids);
        Map<String, Map<String, Object>> detailIdMap = new HashMap<>();
        for (Map<String, Object> detail : details) {
            detailIdMap.put(detail.get("id").toString(), detail);
        }

        // 将元素列表中增加附加属性
        for (VocabElementDto dto : list) {
            Map<String, Object> detail;
            if ((detail = detailIdMap.get(dto.getId().toString())) != null) {
                dto.setChanges((String) detail.get("changes"));
                dto.setCheckFlag(detail.get("check_flag") == null ? "" : detail.get("check_flag") + "");
                dto.setSplitWord((String) detail.get("split_word"));
                dto.setSplitProperty((String) detail.get("split_property"));
            }
        }

        // 处理元素中的展现信息
        setShowInfo(list);

        return list;
    }

    private void setShowInfo(List<VocabElementDto> list) {
        String changes;
        for (VocabElementDto vocabElement : list) {
            String[] sentence = VocabUtils.getSentenceAndShowSentence(vocabElement.getSentence());
            vocabElement.setSentence(sentence[0]);
            vocabElement.setShowSentence(sentence[1]);

            changes = vocabElement.getChanges();
            List<VocabElementChangeRuleDto> changeRuleElements = new ArrayList<>();
            vocabElement.setChangesShow(changes.replace("|","\n").replace("@","\t"));
            VocabElementChangeRuleDto result;
            if (changes != null && !changes.isEmpty()) {
                String[] changeSplits = changes.split("\\|");
                for (String changeSplit : changeSplits) {
                    List<VocabElementChangeDto> changeElements = new ArrayList<>();
                    String[] changeValues = changeSplit.split("@");
                    for(String changeValue:changeValues){
                        VocabElementChangeDto changeElement = new VocabElementChangeDto();
                        changeElement.setrVocabulary(changeValue.split(",")[0]);
                        changeElement.setrProperty(changeValue.split(",")[1]);
                        changeElement.setType(Integer.parseInt(changeValue.split(",")[2]));
                        changeElements.add(changeElement);
                    }
                    result = new VocabElementChangeRuleDto();
                    result.setChangeList(changeElements);
                    changeRuleElements.add(result);
                }
            } else {
                List<VocabElementChangeDto> changeElements = new ArrayList<>();
                VocabElementChangeDto changeElement = new VocabElementChangeDto();
                changeElement.setrVocabulary(vocabElement.getVocabulary());
                changeElement.setrProperty(vocabElement.getReplaceProp() == null ? vocabElement.getProperty()
                        : vocabElement.getReplaceProp());
                changeElement.setType(VocabElementChangeDto.TYPE_SPLIT_NOT_COORDINATE);
                changeElements.add(changeElement);
                result = new VocabElementChangeRuleDto();
                result.setChangeList(changeElements);
                changeRuleElements.add(result);
            }
            vocabElement.setChangeElements(changeRuleElements);

            String slang = vocabElement.getSlang();
            vocabElement.setSlang(slang != null && slang.isEmpty() ? " " : slang);
        }
    }

    private void setListParam(Map<String, Object> param, int startIndex, Integer countPerPage, String propertyKey,
                              Integer flag) {
        param.put("countPerPage", countPerPage);
        param.put("startIndex", startIndex);

        if (BaseContants.FLAG_NULL.equals(flag)) {
            if (StringUtils.equals(propertyKey, VocabConstant.ELEMENT_REASON)) {
                param.put("orderStr", "a.gmt_modified desc,a.vocabulary");
            } else {
                param.put("orderStr", "a.vocabulary");
            }
        } else if (flag.equals(BaseContants.FLAG_RIGHT) && StringUtils.equals(propertyKey, "t")) {
            param.put("orderStr", "a.quantization asc");
        } else if (flag.equals(BaseContants.FLAG_RIGHT)
                && StringUtils.equals(propertyKey, VocabConstant.ELEMENT_REASON)) {
            param.put("orderStr", "char_length(a.vocabulary) desc,a.vocabulary");
        } else {
            param.put("orderStr", "a.gmt_modified desc");
        }
    }

    private Map<String, Object> getSearchMap(String keyword, boolean exactFlag, String replaceTypeKey,
                                             String propertyKey, Integer flag, Integer source) {

        Map<String, Object> param = new HashMap<>();
        if (keyword != null && !keyword.isEmpty()) {
            param.put("vocabulary", exactFlag ? keyword : "%" + keyword + "%");
        }
        if (replaceTypeKey != null && !replaceTypeKey.isEmpty()) {
            param.put("replaceType", replaceTypeKey);
        }
        param.put("property", propertyKey);
        param.put("flag", flag);
        param.put("source", source);

        return param;
    }

    public ModelAndView elementReplace(String startStr, String keyword, String propertyKey, String exactSearchFlag,
                                       String replaceTypeKey, String countPerPage) {
        String subType = "replace";
        if (replaceTypeKey != null && !replaceTypeKey.isEmpty()) {
            if ("property".equals(replaceTypeKey)) {
                subType = "replaceProp";
            } else if ("word".equals(replaceTypeKey)) {
                subType = "replaceWord";
            }
        }

        return getSubList(startStr, keyword, propertyKey, null, subType, exactSearchFlag, countPerPage);
    }

    public ReturnData mappingSlang(String id, String slang, User user) {

        vocabElementDao.updateSlang(Long.parseLong(id), slang, user);

        // 如果该词有替换属性，则将替换属性中的替换词语也更改
        VocabElement vocabElement = vocabElementDao.retrieveObjectById(Long.parseLong(id));
        String replaceProp = vocabElement.getReplaceProp();
        if (replaceProp != null && !replaceProp.isEmpty()) {
            VocabElement replacePropElement = vocabElementDao.retrieveObjectByVocabAndProp(vocabElement.getVocabulary(),
                    replaceProp);

            vocabElementDao.updateSlang(replacePropElement.getId(), slang, user);
        }

        return ReturnUtil.success();
    }

    public ModelAndView elementSlang(String startStr, String keyword, String propertyKey, String exactSearchFlag,
                                     String countPerPageStr) {

        return getSubList(startStr, keyword, propertyKey, null, "slang", exactSearchFlag, countPerPageStr);
    }

    /**
     * 根据类型来返回类似的列表
     *
     * @param startStr
     * @param keyword
     * @param propertyKey
     * @param sexKey
     * @param subType
     * @param exactSearchFlag
     * @param countPerPageStr
     * @return
     */
    private ModelAndView getSubList(String startStr, String keyword, String propertyKey, String sexKey, String subType,
                                    String exactSearchFlag, String countPerPageStr) {
        boolean exactFlag = exactSearchFlag != null && exactSearchFlag.equals("1");

        Map<String, Object> param = new HashMap<>();
        if (keyword != null && !keyword.isEmpty()) {
            param.put("vocabulary", exactFlag ? keyword : "%" + keyword + "%");
        }
        if (propertyKey != null && !propertyKey.isEmpty()) {
            param.put("property", propertyKey);
        }
        if (sexKey != null && !sexKey.isEmpty()) {
            param.put("sex", sexKey);
        }
        param.put(subType + "Flag", 1);

        int totalSize = vocabElementDao.retrieveSize(param);

        Map<String, Integer> pageNo;
        if (countPerPageStr != null && !countPerPageStr.isEmpty()) {
            int countPerPage = Integer.parseInt(countPerPageStr);
            pageNo = GetListUtil.getPageNoParam(totalSize, startStr, countPerPage);
            param.put("countPerPage", countPerPage);
        } else {
            pageNo = GetListUtil.getPageNoParam(totalSize, startStr);
        }
        int endPage = pageNo.get("endPage");
        int start = pageNo.get("start");
        int startIndex = pageNo.get("startIndex");

        List<VocabElement> list = new ArrayList<>();

        if (startIndex < totalSize) {
            param.put("startIndex", startIndex);
            if (subType.indexOf("replace") > -1) {
                param.put("orderStr", "replace_vocab");
            } else if (subType.indexOf("slang") > -1) {
                param.put("orderStr", "slang");
            }
            list = vocabElementDao.retrieveList(param);

            for (VocabElement vocabElement : list) {
                String[] sentence = VocabUtils.getSentenceAndShowSentence(vocabElement.getSentence());
                vocabElement.setSentence(sentence[0]);
            }
        }

        Map<String, Object> map = GetListUtil.getReturnMap2(totalSize, start, startIndex, endPage, list, null);

        Map<String, String> showSearch = new LinkedHashMap<>();
        showSearch.put("keyword", "词语");
        map.put("showSearch", showSearch);
        map.put("propertyList", VocabConstant.elementProperty);

        return new ModelAndView("vocab/element_index", map);
    }

    public void elementExport(String property, String keyword, HttpServletResponse resp) throws Exception {
        // 设置respons的头信息
        property = property == null || property.isEmpty() ? "all" : property;
        RespHeaderUtil.setXlsxResp(resp, "小词_" + property);

        Workbook workbook = new XSSFWorkbook(); // 创建文档

        // 根据property和keyword获取同义词列表
        Map<String, Object> param = new HashMap<>();
        if (!"all".equals(property)) {
            param.put("property", property);
        }
        param.put("keyword", keyword);
        param.put("flag", BaseContants.FLAG_RIGHT);
        param.put("orderStr", "property");
        List<VocabElement> synonymList = vocabElementDao.retrieveList(param);

        Sheet sheet = workbook.createSheet(property); // 创建Sheet
        // 循环写入数据
        Cell cell = null;
        for (int i = 0; i < synonymList.size(); i++) {
            VocabElement vocabElement = synonymList.get(i);

            Row row = sheet.createRow(i);
            cell = row.createCell(0);
            cell.setCellValue(vocabElement.getVocabulary());
            cell = row.createCell(1);
            cell.setCellValue(vocabElement.getProperty());
            cell = row.createCell(2);
            cell.setCellValue(vocabElement.getReplaceVocab());
        }

        OutputStream os = resp.getOutputStream();
        workbook.write(os);

        os.close();
        workbook.close();
    }

    public ModelAndView elementSexAgeList(String startStr, String keyword, Integer status, String propertyKey,
                                          String sexKey, String exactSearchFlag, String countPerPageStr) {
        if (status == 0) {
            return getSubList(startStr, keyword, propertyKey, sexKey, "sexAge1", exactSearchFlag, countPerPageStr);
        } else {
            return getSubList(startStr, keyword, propertyKey, sexKey, "sexAge2", exactSearchFlag, countPerPageStr);
        }
    }

    public ReturnData setSex(String id, String sex, User user) {
        VocabElement m = vocabElementDao.retrieveObjectById(Long.parseLong(id));
        //该词的一个同义词的属性
        VocabElement n = vocabElementDao.getsynonymyelement(id);
        if (n != null && m.getSexAgeFlag() != 1) {
            String synSex = n.getSex().toString();
            String synVocab = n.getVocabulary();
            if (sex.equals(synSex)) {
                vocabElementDao.setSynSex(id, sex, user);
            } else {
                String synSexShow = synSex.replace("0", "无性别").replace("1", "男").replace("2", "女");
                ReturnCode rc = ReturnCode.SETAGE_ERROR;
                rc.setDesc("勾选已被阻止" + "\n" + "原因：修改内容与该词的同义词不符" + "\n" + synVocab + "\n" + synSexShow);
                return ReturnUtil.fail(rc);
            }
        }else{
            //根据同义词先更新
            int updateNum = vocabElementDao.setSynSex(id, sex, user);
            if(updateNum == 0){
                // 不存在同义词直接修改该词
                vocabElementDao.setSex(id, sex, user);
            }
        }

        return ReturnUtil.success();
    }

    public ReturnData setAge(String id, String age, Boolean flag, User user) {
        VocabElement m = vocabElementDao.retrieveObjectById(Long.parseLong(id));

        if (flag) {
            // flag为true则添加该年龄段
            if (m.getAge() == null || !m.getAge().contains(age)) {
                age = (m.getAge() == null ? "" : m.getAge()) + age + ";";
            }
        } else {
            // flag为true则去除该年龄段
            if (m.getAge() != null) {
                age = m.getAge().replace(age + ";", "");
            }
        }
        //该词的一个同义词的属性
        VocabElement n = vocabElementDao.getsynonymyelement(id);
        if (n != null ) {
            // 如果是已校验的直接修改同义词
            if(m.getSexAgeFlag() == 1){
                vocabElementDao.setSynAge(id, age, user);
            }else{
                String synAge = n.getAge() == null? "":n.getAge();
                String synVocab = n.getVocabulary();
                Integer synSex = n.getSex();
                if (age.equals(synAge) && m.getSex().equals(synSex)) {
                    vocabElementDao.setSynAge(id, age, user);
                } else {
                    String synSexShow = synSex.toString().replace("0", "无性别").replace("1", "男").replace("2", "女");
                    ReturnCode rc = ReturnCode.SETAGE_ERROR;
                    rc.setDesc("勾选已被阻止" + "\n" + "原因：修改内容与该词的同义词不符" + "\n" + synVocab + "\n" + synSexShow + "\n" + synAge);
                    return ReturnUtil.fail(rc);
                }
            }
        } else {
            //根据同义词先更新
            int updateNum = vocabElementDao.setSynAge(id, age, user);
            if(updateNum == 0){
                // 不存在同义词直接修改该词
                vocabElementDao.setAge(id, age, user);
            }
        }
        return ReturnUtil.success();
    }

    public ReturnData submitSexAge(String ids, User user) {
        if (ids != null && !ids.isEmpty()) {
            if (ids.lastIndexOf(",") == ids.length() - 1) {
                ids = ids.substring(0, ids.length() - 1);
            }
            vocabElementDao.submitSexAge(ids, user);
        }
        return ReturnUtil.success();
    }

    public void exportSexAge(HttpServletResponse resp) throws Exception {
        RespHeaderUtil.setXlsxResp(resp, "小词年龄性别");

        Workbook workbook = new XSSFWorkbook(); // 创建文档

        // 根据property和keyword获取同义词列表
        Map<String, Object> param = new HashMap<>();
        param.put("flag", BaseContants.FLAG_RIGHT);
        param.put("sexAge2Flag", "1");
        param.put("orderStr", "property");
        List<VocabElement> synonymList = vocabElementDao.retrieveList(param);

        Sheet sheet = workbook.createSheet(); // 创建Sheet
        // 循环写入数据
        Cell cell = null;
        for (int i = 0; i < synonymList.size(); i++) {
            VocabElement vocabElement = synonymList.get(i);

            String age = vocabElement.getAge() == null ? "" : vocabElement.getAge();
            Row row = sheet.createRow(i);
            cell = row.createCell(0);
            cell.setCellValue(vocabElement.getVocabulary());
            cell = row.createCell(1);
            cell.setCellValue(vocabElement.getProperty());
            cell = row.createCell(2);
            if (vocabElement.getSex() == 1) {
                cell.setCellValue("男");
            } else if (vocabElement.getSex() == 2) {
                cell.setCellValue("女");
            }
            String[] ages = age.split(";");
            Map<String, Integer> ageMap = getAgeMap(ages);
            int j = 3;
            for (String temp : ageMap.keySet()) {
                if (ageMap.get(temp) == 1) {
                    cell = row.createCell(j);
                    cell.setCellValue(temp);
                    j++;
                }
            }
        }

        OutputStream os = resp.getOutputStream();
        workbook.write(os);

        os.close();
        workbook.close();
    }

    private Map<String, Integer> getAgeMap(String[] ages) {
        Map<String, Integer> ageMap = new LinkedHashMap<>();
        for (String age : BusinessContants.ageArray) {
            ageMap.put(age, 0);
        }
        for (String age : ages) {
            ageMap.put(age, 1);
        }
        return ageMap;
    }

    /**
     * 根据词语和属性以及添加人增加小词数据
     *
     * @param vocab
     * @param prop
     * @param user
     */
    private VocabElement addElement(String vocab, String prop, User user) {
        VocabElement element = new VocabElement();
        element.setVocabulary(vocab);
        element.setProperty(prop);
        element.setFlag(BaseContants.FLAG_RIGHT);
        element.setCnt(0);
        element.setSentence("");
        element.setModifierId(user.getUserId());
        element.setModifierName(user.getRealName());

        Long id = vocabElementDao.insert(element);
        vocabElementDao.insertSource(id);
        return element;
    }

    /**
     * 根据一个词语列表和属性获取频数最大的词语，如果系统中没有该类词，则返回空字符串
     *
     * @param words
     * @param property
     * @return
     */
    public String retrieveTheLargestCntWordByWords(List<String> words, String property) {
        VocabElement element = vocabElementDao.retrieveTheLargestCntWordByWords(words, property);

        if (element != null) {
            return element.getVocabulary();
        }

        return "";
    }

    @Autowired
    private VocabElementChangeDao vocabElementChangeDao;

    private VocabElementChange getChangeByParam(Long eid, Long rid, String splitNode) {
        VocabElementChange change = new VocabElementChange();
        change.setEid(eid);
        change.setRid(rid);
        if ("1".equals(splitNode)) {
            change.setType(VocabElementChange.TYPE_SPLIT_COORDINATE);
        } else {
            change.setType(VocabElementChange.TYPE_SPLIT_NOT_COORDINATE);
        }
        return change;
    }

    public ReturnData checkPage(String[] dataIds, String[] flags, String[] replaceVocabs, String[] replaceProps,
                                String[] splitValues, User user) {
        StringBuffer errMsg = new StringBuffer();
        // 先将数据维护好
        for (int i = 0; i < dataIds.length; i++) {
            Long id = Long.parseLong(dataIds[i]);
            Integer flag = Integer.parseInt(flags[i]);
            String replaceVocab = replaceVocabs[i].trim().isEmpty() ? null : replaceVocabs[i].trim();
            String replaceProp = replaceProps[i].trim().isEmpty() ? null : replaceProps[i].trim();
            String splitValue = splitValues[i].trim();
            errMsg.append(updateElement(id, flag, replaceVocab, replaceProp, splitValue, user));
        }
        LOGGER.info("Update all element end!");

        ReturnData rd = checkAll();

        if (!rd.getReturnCode().getCode().equals(ReturnCode.SUCCESS.getCode())) {
            errMsg.append(rd.getReturnCode().getDesc());
        }

        if (errMsg.length() > 0) {
            throw new RuntimeException("校验结果：\n" + errMsg.toString());
        } else {
            // 将替换结果、拆分结果是未校验的直接设置为正确
            vocabElementDao.checkChangeResult();

            // 初始化通配符
            vocabElementWildcardService.initAll();
        }

        return ReturnUtil.success();
    }

    private String getClashStr(VocabElementClashDto c) {
        String s1 = getElementReplaceStr(c.getVocabulary1(), c.getProperty1(), c.getReplaceVocab1(),
                c.getReplaceProp1());
        String s2 = getElementReplaceStr(c.getVocabulary2(), c.getProperty2(), c.getReplaceVocab2(),
                c.getReplaceProp2());

        return s1 + "->" + s2;
    }

    private String updateElement(Long id, Integer flag, String replaceVocab, String replaceProp, String splitValue,
                                 User user) {
        LOGGER.info("Update element begin id=" + id);
        // 获取元素数据
        VocabElement element = vocabElementDao.retrieveObjectById(id);
        String vocabulary = element.getVocabulary();
        String property = element.getProperty();
        LOGGER.info("Get element by id end,vocabulary=" + vocabulary + ",property=" + property);

        // 如果有前置词则维护前置词
        String replaceVocabErrMsg = "";
        String replacePropErrMsg = "";
        String errMsg = "";
        List<VocabElement> preElementList = vocabElementDao.retrievePreElementList(vocabulary, property, id);
        if (preElementList != null && !preElementList.isEmpty()) {
            for (VocabElement preElement : preElementList) {
                if (replaceVocab != null && preElement.getReplaceVocab() != null) {
                    replaceVocabErrMsg += getElementReplaceStr(preElement) + "->" + getElementReplaceStr(element) + ",";
                } else if (replaceProp != null && preElement.getReplaceProp() != null) {
                    replacePropErrMsg += getElementReplaceStr(preElement) + "->" + getElementReplaceStr(element) + ",";
                }
            }
            if (replaceVocabErrMsg.isEmpty() && replacePropErrMsg.isEmpty()) {
                // 如果没有冲突则将前置词维护
                for (VocabElement preElement : preElementList) {
                    if (replaceVocab != null && preElement.getReplaceVocab() == null) {
                        preElement.setReplaceVocab(replaceVocab);
                    }
                    if (replaceProp != null && preElement.getReplaceProp() == null) {
                        preElement.setReplaceProp(replaceProp);
                    }
                    preElement.setModifierId(user.getUserId());
                    preElement.setModifierName(user.getRealName());
                    vocabElementDao.update(preElement);
                }
                LOGGER.info("Pre element update end!");
            } else {
                errMsg = "前置词与当前词同时存在替换词语或替换属性：" + replaceVocabErrMsg + replacePropErrMsg + "\n";
            }
        }

        // 查找是否有元素的替换后词语，如果不存在则添加一个正确的词语
        if (replaceVocab != null || replaceProp != null) {
            String vocab = replaceVocab == null ? vocabulary : replaceVocab;
            String prop = replaceProp == null ? property : replaceProp;
            VocabElement replaceElement = vocabElementDao.retrieveObjectByVocabAndProp(vocab, prop);
            if (replaceElement == null) {
                replaceElement = addElement(replaceVocab != null ? replaceVocab : vocabulary,
                        replaceProp != null ? replaceProp : property, user);
            }
        }
        // 出现替换词语且没有替换属性 ,添加同义词.如果存在在两组同义词中则不允许添加,在一组中就添加另一个词,没有同义词则新增
        if (StringUtils.isNotBlank(replaceVocab) && StringUtils.isBlank(replaceProp)) {
            List<SynonymyWord> value1 = synonymyWordDao.retrieveByWordProperty(property, vocabulary);
            List<SynonymyWord> value2 = synonymyWordDao.retrieveByWordProperty(property, replaceVocab);
            if ((value1 != null && value1.size() == 1) && (value2 == null || value2.size() == 0)) {
                // 新增同义词
                SynonymyWord sw = new SynonymyWord();
                sw.setModifierId(user.getUserId());
                sw.setProperty(property);
                sw.setSynonymyId(value1.get(0).getSynonymyId());
                sw.setType(1);
                sw.setWord(replaceVocab);
                sw.setModifierName(user.getRealName());
                synonymyWordDao.insert(sw);
            } else if ((value2 != null && value2.size() == 1) && (value1 == null || value1.size() == 0)) {
                // 新增同义词
                SynonymyWord sw = new SynonymyWord();
                sw.setModifierId(user.getUserId());
                sw.setProperty(property);
                sw.setSynonymyId(value2.get(0).getSynonymyId());
                sw.setType(1);
                sw.setWord(vocabulary);
                sw.setModifierName(user.getRealName());
                synonymyWordDao.insert(sw);
            } else if ((value2 != null && value2.size() == 1) && (value1 != null && value1.size() == 1)) {
                // 校验是否synonymyid相同
                if (!(value2.get(0).getSynonymyId() + "").equals(value1.get(0).getSynonymyId() + "")) {
                    errMsg = "替换词语在两组不同的同义词中" + vocabulary + "," + replaceVocab + "\n";
                }
            } else {
                // 新增一组同义词
                Synonymy synonymy = new Synonymy();
                synonymy.setStd(replaceVocab);
                synonymy.setWords("\t" + replaceVocab + "\t" + vocabulary + "\t");
                String reg = "^[u0391-uFFE5/!@#$%^&*()_+-=,./;\\<>?:{}|`~]*$";
                if (replaceVocab.matches(reg)) {
                    synonymy.setEnglishStd(replaceVocab);
                    synonymy.setChineseStd("");
                } else {
                    synonymy.setEnglishStd("");
                    synonymy.setChineseStd(replaceVocab);
                }
                synonymy.setProperty(property);
                synonymy.setType(1);
                synonymy.setModifierId(user.getUserId());
                synonymy.setModifierName(user.getRealName());
                long synonymyId = synonymyDao.insert(synonymy);
                List<String> words = new ArrayList<>();
                words.add(vocabulary);
                words.add(replaceVocab);
                synonymyWordDao.batchInsert(synonymyId, words, user, synonymy.getType(), property);
            }

        }

        // 修改元素
        element.setFlag(flag);
        // 如果存在拆分则没有替换
        if (splitValue != null && !splitValue.isEmpty()) {
            element.setReplaceProp(null);
            element.setReplaceVocab(null);
        } else {
            element.setReplaceProp(replaceProp);
            element.setReplaceVocab(replaceVocab);
        }
        element.setModifierId(user.getUserId());
        element.setModifierName(user.getRealName());
        vocabElementDao.update(element);

        // 维护分拆数据
        List<VocabElementChange> changes = new ArrayList<>();
        // 先删除该元素的规则
        vocabElementChangeDao.deleteSplitByEid(id);
        if (splitValue != null && !splitValue.isEmpty()) {
            // 维护规则
            String[] rules = splitValue.substring(0,splitValue.length()-1).split("\\|");
            for(String rule:rules){

                // 先插入规则
                Long ruleId = vocabElementDao.insertChangeRule(id);
                String[] splitVocabs = rule.split(",");
                for (int i = 0; i < splitVocabs.length; i++) {
                    String[] splitVocab = splitVocabs[i].split(" ");
                    String splitWord = splitVocab[1];
                    String splitNode = splitVocab[0];
                    String splitProperty = splitVocab[2];

                    // 出现过一次属性为空，未重现，暂时拦住并返回错误
                    if (splitProperty.isEmpty()) {
                        return "词语“" + splitWord + "”的属性为空，请校验！";
                    }

                    VocabElement splitElement = vocabElementDao.retrieveObjectByVocabAndProp(splitWord, splitProperty);
                    LOGGER.info("Get split element success!Word={},property={}", new Object[]{splitWord, splitProperty});

                    // 无拆分后词语
                    if (splitElement == null) {
                        splitElement = addElement(splitWord, splitProperty, user);
                    }
                    // 将参数转化为实体
                    changes.add(getChangeByParam(splitElement.getId(),ruleId , splitNode));
                }
            }
        }

        // 将分拆数据添加入数据库
        vocabElementChangeDao.insertBatch(changes);
        LOGGER.info("Insert changes success!eid=" + id);

        // 如果替换词语存在则物理删除近义词中该标准词
        if (replaceVocab != null) {
            String std = element.getVocabulary();
            homoionymSearchTermsService.physicalDelete(std);
            LOGGER.info("Delete homoionymSearchTerms success!");
        }

        return errMsg;
    }

    private String getElementReplaceStr(VocabElement e) {
        return getElementReplaceStr(e.getVocabulary(), e.getProperty(), e.getReplaceVocab(), e.getReplaceProp());
    }

    private String getElementReplaceStr(String v, String p, String rv, String rp) {
        StringBuffer sb = new StringBuffer();
        sb.append("(");
        sb.append(v);
        sb.append(" ");
        sb.append(p);
        sb.append(" ");
        sb.append(rv == null ? "-" : rv);
        sb.append(" ");
        sb.append(rp == null ? "-" : rp);
        sb.append(")");
        return sb.toString();
    }

    public ReturnData checkAll() {

        StringBuffer errMsg = new StringBuffer();

        // 校验替换后词语必须不是错误的
        List<VocabElementClashDto> clashList2 = vocabElementDao.retrieveReplaceResultWrong();
        if (!clashList2.isEmpty()) {
            String clashMsg = "";
            for (VocabElementClashDto clash : clashList2) {
                clashMsg += getClashStr(clash) + ",";
            }
            errMsg.append("替换后词语不是正确的元素：");
            errMsg.append(clashMsg);
            errMsg.append("\n");
        }
        LOGGER.info("Clash list2's size is " + clashList2.size());

        // 校验拆分后的词必须是不是错误的
        List<VocabElementClashDto> clashList3 = vocabElementDao.retrieveSplitResultWrong();
        if (!clashList3.isEmpty()) {
            String clashMsg = "";
            for (VocabElementClashDto clash : clashList3) {
                clashMsg += getClashStr(clash) + ",";
            }
            errMsg.append("拆分后不是正确的元素：");
            errMsg.append(clashMsg);
            errMsg.append("\n");
        }
        LOGGER.info("Clash list3's size is " + clashList3.size());

        if (errMsg.length() > 0) {
            ReturnCode rc = ReturnCode.ELEMENT_CHECK_PAGE_ERROR;
            rc.setDesc(errMsg.toString());
            return ReturnUtil.fail(rc);
        }

        return ReturnUtil.success();
    }

    private void addSynonymy(long id, List<String> allWord, User user) {
        Synonymy synonymyValue = synonymyDao.retrieveObjectById(id);
        if (synonymyValue != null) {
            List<String> addWord = new ArrayList<>();
            String words = synonymyValue.getWords();
            List<String> wordList = CollectionUtil.getListByArray(words.substring(1, words.length()).split("\t"));
            for (String word : allWord) {
                if (!wordList.contains(word)) {
                    words += word;
                    words += "\t";
                    addWord.add(word);
                }
            }
            synonymyValue.setWords(words);
            synonymyValue.setModifierName(user.getRealName());
            if (addWord.size() > 0) {
                synonymyDao.update(synonymyValue);
                // 添加word
                synonymyWordDao.batchInsert(id, addWord, user, 1, "r");
            }
        }
    }

    private void addNewSynonymy(List<String> allWord, String std, User user) {
        // 新增同义词
        StringBuffer words = new StringBuffer();
        words.append("\t");
        for (String word : allWord) {
            words.append(word).append("\t");
        }
        Synonymy sy = new Synonymy();
        sy.setWords(words.toString());
        sy.setStd(std);
        String regEx = "[\u4E00-\u9FA5]";
        Pattern p = Pattern.compile(regEx);
        // 判断是中文标准词
        if (p.matcher(sy.getStd()).find()) {
            sy.setChineseStd(sy.getStd());
            sy.setEnglishStd("");
        } else {
            sy.setEnglishStd(sy.getStd());
            sy.setChineseStd("");
        }
        sy.setModifierName(user.getRealName());
        sy.setProperty("r");
        sy.setModifierId(user.getUserId());
        sy.setType(1);
        long id = synonymyDao.insert(sy);
        synonymyWordDao.batchInsert(id, allWord, user, 1, "r");
    }

    public ReturnData elementRAddSynonymy(String ids, String std, User user) {
        List<String> allWord = new ArrayList<>();
        std = std.trim();
        allWord.add(std);
        List<VocabElement> vocabs = vocabElementDao.retrieveByIds(ids.substring(0, ids.length() - 1));
        for (VocabElement vocab : vocabs) {
            if (!allWord.contains(vocab.getVocabulary())) {
                allWord.add(vocab.getVocabulary());
            }
        }
        // 判断是否存在同义词,
        List<Map<String, String>> synonymyIdAndWords = synonymyWordDao.retrieveSynonymyIdByWords(allWord, "r");
        Set<String> checkSynonymyId = new HashSet<>();
        Map<String, String> idAndWordMap = new HashMap<>();
        for (Map<String, String> synonymyIdAndWord : synonymyIdAndWords) {
            idAndWordMap.put(synonymyIdAndWord.get("synonymy_id"), synonymyIdAndWord.get("word"));
            checkSynonymyId.add(synonymyIdAndWord.get("synonymy_id"));
        }
        // 如果存在同义词冲突不允许添加
        if (checkSynonymyId.size() > 1) {
            ReturnCode rc = ReturnCode.ELEMENT_CHECK_PAGE_ERROR;
            String[] checkId = new String[]{};
            checkId = checkSynonymyId.toArray(checkId);
            StringBuffer err = new StringBuffer();
            for (String id : checkId) {
                err.append(idAndWordMap.get(id)).append(";");
            }
            rc.setDesc("存在同义词冲突,不允许添加:" + err.toString());
            return ReturnUtil.fail(rc);
        } else if (checkSynonymyId.size() == 1) {
            // 添加入该同义词中
            String[] id = new String[]{};
            id = checkSynonymyId.toArray(id);
            addSynonymy(Long.parseLong(id[0]), allWord, user);
        } else {
            // 新增同义词
            addNewSynonymy(allWord, std, user);
        }

        return ReturnUtil.success();
    }

    public ReturnData elementRCheckAnalysis(String id, String analysisFlag, User user) {

        vocabElementDao.updateAnalysisFlag(Long.parseLong(id), analysisFlag);

        return ReturnUtil.success();
    }

    /**
     * 初始化性别年龄同义词数据
     */
    public void initSexAgeSynonymy(){
        vocabElementDao.initSexAgeSynonymy();
    }
}
